Add mac build to travis CI (#179)
authortsteven4 <tsteven4@users.noreply.github.com>
Mon, 21 May 2018 22:39:44 +0000 (16:39 -0600)
committerGitHub <noreply@github.com>
Mon, 21 May 2018 22:39:44 +0000 (16:39 -0600)
Add mac build to travis CI.
Deploy mac dmg to github releases from travis.
Deploy windows installer to github releases from appveyor.

22 files changed:
.travis.yml
GPSBabel.pro
appveyor.yml
docker_hook [deleted file]
gui/app.pro
gui/help/gpsbabel.html [deleted file]
gui/makelinuxdist.sh.in
gui/setup.iss
gui/upgrade.cc
tools/qtci/LICENSE [new file with mode: 0644]
tools/qtci/README.gpsbabel [new file with mode: 0644]
tools/qtci/README.md [new file with mode: 0644]
tools/qtci/extract-qt-installer [new file with mode: 0644]
tools/qtci/qt-5.9.5-osx [new file with mode: 0755]
tools/travis_install_osx [new file with mode: 0755]
tools/travis_script_linux_docker [new file with mode: 0755]
tools/travis_script_osx [new file with mode: 0755]
tools/uploadtool/LICENSE [new file with mode: 0644]
tools/uploadtool/README.gpsbabel [new file with mode: 0644]
tools/uploadtool/README.md [new file with mode: 0644]
tools/uploadtool/upload.sh [new file with mode: 0755]
tools/uploadtool/upload_appveyor.sh [new file with mode: 0755]

index 03774665118c843b49ad0f1ea2b82308f3b2be64..609ea8a25c3c43f32514a0c02f3957858dc0243a 100644 (file)
@@ -1,7 +1,37 @@
-sudo: required
-services: docker
-env:
-  - CC=gcc CXX=g++
-  - CC=clang CXX=clang++
+language: cpp
+
+matrix:
+  include:
+    - os: linux
+      dist: trusty
+      sudo: required
+      services: docker
+      compiler: gcc
+    - os: linux
+      dist: trusty
+      sudo: required
+      services: docker
+      compiler: clang
+    - os: osx
+      compiler: clang
+      cache:
+        directories:
+          - $HOME/Qt
+
+install:
+  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then source ./tools/travis_install_osx; fi
+
 script:
-  - ./docker_hook
+  - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./tools/travis_script_linux_docker; fi 
+  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./tools/travis_script_osx; fi
+
+after_success:
+  - cd ${TRAVIS_BUILD_DIR}
+  # only deploy pushes to master or prs that target master.  the prs will go to transfr.sh, the pushes go to github.
+  - if [ "${TRAVIS_OS_NAME}" = "osx" ] && [ "$TRAVIS_BRANCH" = "master" ]; then bash ./tools/uploadtool/upload.sh  gui/objects/GPSBabel-*.dmg; fi
+
+branches:
+  except:
+    - /^(?i:continuous)$/  # Do not build tags that we create when we upload to GitHub Releases
+    - /^(?i:continuous.*windows)$/  # Do not build tags that we create when we upload to GitHub Releases
+
index 96154c1c2b767fb00ba04d300ecde34af50e324c..10ef22de10026bfe87958c906cd055f1acc0673d 100644 (file)
@@ -197,3 +197,9 @@ DEFINES += CSVFMTS_ENABLED
 # Citation: http://stackoverflow.com/questions/18667291/disable-wall-compiler-warnings-in-a-qt-project
 QMAKE_CFLAGS_WARN_ON -= -W
 QMAKE_CXXFLAGS_WARN_ON -= -W
+
+macx|linux{
+  check.commands = PNAME=./$(TARGET) ./testo
+  check.depends = $(TARGET)
+  QMAKE_EXTRA_TARGETS += check
+}
index c38b5a263a10e161bcc89d54e7267f7be42f40b2..178bfb251f941faf7dbd8c072d6273be91879464 100644 (file)
@@ -1,6 +1,8 @@
 version: 1.0.{build}
 
 environment:
+  GITHUB_TOKEN:
+    secure: gOkGevzhckv5gwFMhnyRk9JZqn6eaZ4vdVFkRdjL6p6NNZu7mwf8aTfMhWSnhaS2 # your encrypted token from GitHub
   matrix:
   # MinGW gui builds fail with Qt newer than 5.6 as webkit and webengine are missing.
   # MinGW
@@ -49,7 +51,7 @@ build_script:
         # by using the next version of windeployqt which had this
         # bug fixed.
         & ".\tools\make_windows_release.ps1" -windeployqt "C:\Qt\5.6\mingw49_32\bin\windeployqt.exe"
-        $sha=(git rev-parse --short HEAD)
+        $sha=(git rev-parse --short=7 HEAD)
         Get-ChildItem .\gui\release\GPSBabel-*-Setup.exe | % { Push-AppveyorArtifact $_.FullName -FileName "GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Setup.exe" }
         Get-ChildItem .\gui\release\GPSBabel-*-Manifest.txt | % { Push-AppveyorArtifact $_.FullName -FileName "GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Manifest.txt" }
       }
@@ -57,7 +59,7 @@ build_script:
       {
         # full build and deploy of our release configuration
         & ".\tools\make_windows_release.ps1" -gpsbabel_build_dir_name "build-GPSBabel-Desktop_Qt_5_9_MSVC2015_32bit-Release" -gui_build_dir_name "build-app-Desktop_Qt_5_9_MSVC2015_32bit-Release" -mkspec win32-msvc -mkcmd nmake.exe
-        $sha=(git rev-parse --short HEAD)
+        $sha=(git rev-parse --short=7 HEAD)
         Get-ChildItem .\gui\release\GPSBabel-*-Setup.exe | % { Push-AppveyorArtifact $_.FullName -FileName "GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Setup.exe" }
         Get-ChildItem .\gui\release\GPSBabel-*-Manifest.txt | % { Push-AppveyorArtifact $_.FullName -FileName "GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Manifest.txt" }
       }
@@ -89,3 +91,34 @@ test_script:
       C:\msys64\usr\bin\bash.exe -lc "cd $env:projdir; PNAME=./release/GPSBabel.exe GBTEMP=./gbtemp ./test_encoding_utf8 2>&1"
       Write-Host "Finished test_script with exit status $LastExitCode"
       if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode)  }
+
+deploy_script:
+  - ps: |
+      if (($env:platform -eq "x86") -and ($env:qt -eq "5.9\msvc2015") -and ($env:APPVEYOR_REPO_BRANCH -eq "master"))
+      {
+        $env:projdir=(C:\msys64\usr\bin\bash.exe -c "pwd")
+        $env:sha=(C:\msys64\usr\bin\bash.exe -c "git rev-parse --short=7 HEAD")
+        C:\msys64\usr\bin\bash.exe -lc "cd $env:projdir; ls ./gui/release/*.exe"
+        C:\msys64\usr\bin\bash.exe -lc "cd $env:projdir; cp -p ./gui/release/GPSBabel-*-Setup.exe GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Setup.exe"
+        C:\msys64\usr\bin\bash.exe -lc "cd $env:projdir; ./tools/uploadtool/upload_appveyor.sh GPSBabelTest-$($env:APPVEYOR_BUILD_VERSION)-$($sha)-Setup.exe"
+        Write-Host "Finished deploy_script"
+      }
+
+#deploy:
+#  tag: 'continuous windows'
+#  release: 'Continuous windows build'
+#  description: 'Continuous build'
+#  provider: GitHub
+#  auth_token:
+#    secure: gOkGevzhckv5gwFMhnyRk9JZqn6eaZ4vdVFkRdjL6p6NNZu7mwf8aTfMhWSnhaS2 # your encrypted token from GitHub
+#  artifact: /GPSBabel.*Setup.exe/      # upload installer to release assets
+#  draft: false
+#  prerelease: true
+#  on:
+#    branch: master                 # release from master branch only
+#    appveyor_repo_tag: false       # deploy on tag push only
+#    platform: x86
+#    qt: 5.9\msvc2015
+
+skip_tags: true
+
diff --git a/docker_hook b/docker_hook
deleted file mode 100755 (executable)
index 22ec02a..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash -ex
-#
-# setup up and run a docker build.
-# this is used by travis.
-#
-# create the container to run the build and regression.
-# pass the compiler from the travis matrix through CC, CXX.
-# we need the default charmap to be UTF-8 for test_encoding_utf8, explicit set it here through LC_ALL.
-cnt=$(docker create  -v `pwd`:/app -e CC=$CC -e CXX=$CXX -e LC_ALL=C.UTF-8 tsteven4/gpsbabel_build_environment bash -c "./build_and_test")
-# copy the pwd to the container.  travis has got the code user test in the pwd.
-docker cp . $cnt:/app
-# run the container to execute the build and the regression.
-docker start -a $cnt
index 6ff168cff5a5ed56e1f798f973bf61afc063bb18..7d2039b523fb2dc8300afdad4f0b03179124e60c 100755 (executable)
@@ -6,11 +6,6 @@ CONFIG(debug, debug|release) {
   CONFIG += console
 }
 
-# For Mac, x86 and x64, but not PPC binary.   Ignored on other OSes.
-# macx:CONFIG -= x86_64 
-# macx:CONFIG += x86
-macx:DEFINES += HAVE_CONFIG_H
-
 ICON = images/appicon.icns
 
 QT += core \
diff --git a/gui/help/gpsbabel.html b/gui/help/gpsbabel.html
deleted file mode 100644 (file)
index fd07cbc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<p>This is the local help.  It currently isn't very helpful.</p>
-<p>The <a href="http://www.gpsbabel.org/htmldoc-development"> online help 
-   is mo betta.</p>
index 983de11acc4449a4833f8e5eb0c950ec417adc3d..fa022a314a8748a4ecea3be752759ddd4f5aabed 100644 (file)
@@ -9,7 +9,6 @@ rm -rf $DISTDIR
 mkdir $DISTDIR
 mkdir $DISTDIR/plugins
 mkdir $DISTDIR/translations
-mkdir $DISTDIR/help
 
 QT_LIBS="`ldd objects/gpsbabelfe-bin | grep libQt | awk '{print $3}'`"
 QT_LIBS="$QT_LIBS `ldd $QT_INSTALL_PLUGINS/platforms/libqxcb.so | grep libQt | awk '{print $3}'`"
@@ -46,8 +45,6 @@ chmod +x $DISTDIR/gpsbabelfe
 cp objects/gpsbabelfe-bin $DISTDIR
 cp qt.conf $DISTDIR/
 cp ../gpsbabel $DISTDIR/
-#
-cp -r help/*.html $DISTDIR/help
 
 cp ../COPYING $DISTDIR/
 #cp AUTHORS $DISTDIR/
index 4b8e163f5be40739885098a2c3b4463be4015e3c..8ed735cd43598c5428d5f4191633088d10689966 100644 (file)
@@ -49,7 +49,6 @@ Source: "..\{#gui_build_dir_name}\release\*"; Excludes: "app.res,vcredist_*.exe,
 Source: "..\{#gui_build_dir_name}\release\vcredist_x86.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist deleteafterinstall\r
 Source: "..\{#gui_build_dir_name}\release\vcredist_x64.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist deleteafterinstall\r
 Source: "..\..\{#gpsbabel_build_dir_name}\release\gpsbabel.exe";       DestDir: "{app}"; Flags: ignoreversion\r
-; Source: release\help\*;              DestDir: "{app}\help"; Flags: ignoreversion recursesubdirs createallsubdirs\r
 \r
 ; Translation strings extracted from source code.  Include it in the dist\r
 ; so that users can translate if they want to.\r
index 0eac201d3a457167c656350774fb9496614b7201..56ae53276b4fada9bc7181ebcf0ab7f1e1f2c95d 100644 (file)
 #include "format.h"
 #include "upgrade.h"
 #include "../gbversion.h"
-#if HAVE_CONFIG_H
-#include "../config.h"
-#endif
 
 #include <cstdio>
-#if HAVE_UNAME
-#include <sys/utsname.h>
-#endif // HAVE_UNAME
 
 #include <QDebug>
 #include <QDesktopServices>
@@ -81,88 +75,8 @@ bool UpgradeCheck::isTestMode()
   return testing;
 }
 
-// In Qt 5.4, QSysInfo got classes that do this better. Travis is stuck
-// on older version of Qt, so keep it building there for now.
-
-#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
-QString UpgradeCheck::getOsName()
-{
-  // Do not translate these strings.
-#if defined (Q_OS_LINUX)
-    return "Linux";
-#elif defined (Q_OS_MAC)
-  return "Mac";
-#elif defined (Q_OS_WIN)
-  return "Windows";
-#else
-  return "Unknown";
-#endif
-
-}
-// See http://doc.trolltech.com/4.5/qsysinfo.html to interpret results
-QString UpgradeCheck::getOsVersion()
-{
-#if defined (Q_OS_MAC)
-  switch (QSysInfo::MacintoshVersion) {
-  case QSysInfo::MV_10_3: return "10.3"; break;
-  case QSysInfo::MV_10_4: return "10.4"; break;
-  case QSysInfo::MV_10_5: return "10.5"; break;
-  case QSysInfo::MV_10_6: return "10.6"; break;
-  case QSysInfo::MV_10_7: return "10.7"; break;
-  case QSysInfo::MV_10_8: return "10.8"; break;
-  case QSysInfo::MV_10_9: return "10.9"; break;
-  case QSysInfo::MV_10_10: return "10.10"; break;
-  case QSysInfo::MV_10_11: return "10.11"; break;
-  case QSysInfo::MV_10_12: return "10.12"; break;
-  default:
-    if (QSysInfo::MacintoshVersion == 0x000E) {
-      return "10.13";
-      break;
-    }
-    if (QSysInfo::MacintoshVersion == 0x000F) {
-      return "10.14";
-      break;
-    }
-    return QString("Unknown Mac %1").arg(QSysInfo::MacintoshVersion);
-  };
-#elif defined (Q_OS_WIN)
-
-  switch (QSysInfo::WindowsVersion) {
-  // Wildly improbable...
-  case QSysInfo::WV_95: return "95"; break;
-  case QSysInfo::WV_98: return "98"; break;
-  case QSysInfo::WV_Me: return "Me"; break;
-
-  case QSysInfo::WV_4_0: return "NT 4"; break;
-  case QSysInfo::WV_5_0: return "2000"; break;
-  case QSysInfo::WV_5_1: return "XP"; break;
-  case QSysInfo::WV_5_2: return "2003"; break;
-  case QSysInfo::WV_6_0: return "Vista"; break;
-  case QSysInfo::WV_6_1: return "7"; break;
-  default:
-       if (QSysInfo::WindowsVersion == 0x00a0) return "8";
-       if (QSysInfo::WindowsVersion == 0x00b0) return "8.1";
-       if (QSysInfo::WindowsVersion == 0x00c0) return "10.0";
-      return "Windows/Unknown";
-  }
-#endif
-  // FIXME: find something appropriately clever to do for Linux, etc. here.
-  return "Unknown";
-}
-
-QString UpgradeCheck::getCpuArchitecture()
-{
-#if HAVE_UNAME || defined (Q_OS_MAC)
-  struct utsname utsname;
-  if (0 == uname(&utsname)) {
-    return utsname.machine;
-  }
-  return QString();
-#endif
-}
-
-#else // #if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
-
+// Since Qt 5.4 QSysInfo makes it easy to get the OsName,
+// OsVersion and CpuArchitecture.
 QString UpgradeCheck::getOsName()
 {
   return QSysInfo::productType();
@@ -178,8 +92,6 @@ QString UpgradeCheck::getCpuArchitecture()
   return QSysInfo::currentCpuArchitecture();
 }
 
-#endif // #if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
-
 UpgradeCheck::updateStatus UpgradeCheck::checkForUpgrade(
                const QString &currentVersionIn,
                const QDateTime &lastCheckTime,
diff --git a/tools/qtci/LICENSE b/tools/qtci/LICENSE
new file mode 100644 (file)
index 0000000..8dada3e
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/tools/qtci/README.gpsbabel b/tools/qtci/README.gpsbabel
new file mode 100644 (file)
index 0000000..8875a0c
--- /dev/null
@@ -0,0 +1 @@
+The files extract-qt-installer, LICENSE, qt-5.9.5-osx, and README.md are from https://github.com/benlau/qtci
diff --git a/tools/qtci/README.md b/tools/qtci/README.md
new file mode 100644 (file)
index 0000000..0b82511
--- /dev/null
@@ -0,0 +1,154 @@
+# QT-CI
+This project collects a set of script for building Qt application for Android/iOS in command line environment.
+
+[![Build Status](https://travis-ci.org/benlau/qtci.svg?branch=master)](https://travis-ci.org/benlau/qtci)
+
+Check [.travis.yml](https://github.com/benlau/qtci/blob/master/.travis.yml) to see how it works.
+It will demonstrate how to build a apk file using QT-CI scripts.
+
+Installation
+============
+
+Since this project is a collection of script, and the script in bin folder do not have any dependence to each othter.
+It is not necessary to clone / download the whole repository into your build environmnet.
+You may just copy the script you need from this repository.
+
+**recipes/install-qt**
+
+To automaticly install Qt, you can just donwload 2 scripts and give them permition to be executed.
+
+"recipes/install-qt"
+"bin/extract-qt-installer"
+
+Then just run scritp "recipes/install-qt" with desiered verion of Qt
+Example:
+
+       bash install-qt 5.9.4
+Enviroument variables
+=====================
+
+QT_CI_PACKAGES - packages to install. You can check availble packages if set VERBOSE to 1.
+
+Example:
+
+       export VERBOSE=1
+       export QT_CI_PACKAGES=qt,qt.594,qt.594.gcc_64,qt.594.doc.qtvirtualkeyboard
+
+Setup
+=====
+
+    git clone https://github.com/benlau/qtci.git
+
+    source qtci/path.env #Add qtci/bin and qtci/recipes to $PATH
+
+
+Script
+======
+
+**(1) bin/extract-qt-installer**
+--------------------------------
+
+Extract installer of Qt to target path (for Qt 5.5 or above)
+
+Example:
+
+       extract-qt-installer qt-opensource-linux-x64-android-5.5.1.run ~/Qt
+
+**Remarks: The installation path must be absolute path**
+
+Environment Variables
+
+       VERBOSE [Optional] Set to "true" will enable VERBOSE output
+       QT_CI_PACKAGES [Optional] Select the components to be installed instead of using default (eg. QT_CI_PACKAGES="qt.59.gcc_64")
+
+
+
+**(2) bin/extract-ifw**
+--------------------------------
+
+Extract installer of "Qt installer framework" to target path
+
+Example:
+
+       extract-ifw qt-installer-framework-opensource-1.5.0-x64.run ~/QtIfw
+
+**(3) bin/install-android-sdk**
+--------------------------------
+
+Download and install Android SDK
+
+Example:
+
+       install-android-sdk platform-tool,build-tools-20.0.0,android-19
+
+**(4) bin/build-android-gradle-project**
+--------------------------------
+
+Build a Qt Android project and sign the APK
+
+Usage:
+
+       build-android-gradle-project project.pro
+
+Required Environment Variables
+
+       QT_HOME [Required] The home directory of installed Qt. (e.g ~/Qt/5.7)
+       KEYSTORE [Optional] The location of keystore. If it is set, it will be used to sign the created apk
+       KEYALIAS [Optional] The alias of the keystore
+       KEYPASS  [Optional] The password of keystore.
+        ANDROID_TARGET_SDK_VERSION [Optional] Target Android SDK version. The default value is "19"
+
+(5) bin/increase-android-version-code
+--------------------------------
+
+Usage
+
+    increase-android-version-code AndroidManifest.xml
+
+Given a AndroidManifest.xml file, it will increase the value of versionCode field by one.
+
+(6) bin/run-unittests
+----------------------
+
+Usage
+
+    run-unittests project.pro
+
+Build and run an unit test project in current folder. If qpm.json was found, it will call `qpm install` first.
+
+Recipes
+=======
+
+
+In the folder "recipes", it contains a set of script that could download and install specific Qt toolchains for different environment. (Include Android)
+
+Please feel free to modify and submit new recipe.
+
+Example
+
+       apt-get install openjdk-8-jdk p7zip
+
+       source path.env #Add $PWD/bin and $PWD/recipes to $PATH
+
+       #Change to installation path
+
+       qt-5.5.1-android-19 # Install Qt 5.5.1 and Android SDK
+       
+       source qt-5.5.1-android-19.env # Add installed Qt path to $PATH
+
+
+Reference
+=========
+
+ 1. [Continuous distribution for Qt applications on desktop and mobile](http://www.slidedeck.io/lasconic/qtci-qtcon2016)
+ 1. [Andrew's Articles - Continuous deployment for Qt applications](http://andrewdolby.com/articles/2016/continuous-deployment-for-qt-applications/)
+
+Related Projects
+=================
+
+ 1. [benlau/quickpromise](https://github.com/benlau/quickpromise) - Promise library for QML
+ 2. [benlau/quickcross](https://github.com/benlau/quickcross) - QML Cross Platform Utility Library
+ 3. [benlau/qsyncable](https://github.com/benlau/qsyncable) - Synchronize data between models
+ 4. [benlau/testable](https://github.com/benlau/testable) - QML Unit Test Utilities
+ 5. [benlau/quickflux](https://github.com/benlau/quickflux) - Message Dispatcher / Queue for Qt/QML
+ 6. [benlau/biginteger](https://github.com/benlau/biginteger) - QML BigInteger library
diff --git a/tools/qtci/extract-qt-installer b/tools/qtci/extract-qt-installer
new file mode 100644 (file)
index 0000000..545fdcf
--- /dev/null
@@ -0,0 +1,170 @@
+#!/bin/bash
+# QT-CI Project
+# License: Apache-2.0
+# https://github.com/benlau/qtci
+
+set -e #quit on error
+
+if [ $# -lt 2 ];
+then
+    echo extract-qt-installer qt-installer output_path
+    exit -1
+fi
+
+export PATH=$PATH:$PWD
+export WORKDIR=$PWD
+INSTALLER=$1
+OUTPUT=$2
+SCRIPT="$(mktemp /tmp/tmp.XXXXXXXXX)"
+PACKAGES=$QT_CI_PACKAGES
+
+if [[ ! "${OUTPUT:0:1}" = "/" ]] 
+then 
+    echo output path must be an absolute path
+    exit -1
+fi
+
+cat <<EOF > $SCRIPT
+
+function abortInstaller()
+{
+    installer.setDefaultPageVisible(QInstaller.Introduction, false);
+    installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
+    installer.setDefaultPageVisible(QInstaller.ComponentSelection, false);
+    installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false);
+    installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false);
+    installer.setDefaultPageVisible(QInstaller.PerformInstallation, false);
+    installer.setDefaultPageVisible(QInstaller.LicenseCheck, false);
+
+    var abortText = "<font color='red' size=3>" + qsTr("Installation failed:") + "</font>";
+
+    var error_list = installer.value("component_errors").split(";;;");
+    abortText += "<ul>";
+    // ignore the first empty one
+    for (var i = 0; i < error_list.length; ++i) {
+        if (error_list[i] !== "") {
+            log(error_list[i]);
+            abortText += "<li>" + error_list[i] + "</li>"
+        }
+    }
+    abortText += "</ul>";
+    installer.setValue("FinishedText", abortText);
+}
+
+function log() {
+    var msg = ["QTCI: "].concat([].slice.call(arguments));
+    console.log(msg.join(" "));
+}
+
+function Controller() {
+    installer.installationFinished.connect(function() {
+        gui.clickButton(buttons.NextButton);
+    });
+    installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes);
+    installer.setMessageBoxAutomaticAnswer("installationErrorWithRetry", QMessageBox.Ignore);
+}
+
+Controller.prototype.WelcomePageCallback = function() {
+    log("Welcome Page");
+    gui.clickButton(buttons.NextButton, 3000);
+}
+
+Controller.prototype.CredentialsPageCallback = function() {
+    gui.clickButton(buttons.CommitButton);
+}
+
+Controller.prototype.ComponentSelectionPageCallback = function() {
+
+    var components = installer.components();
+    log("Available components: " + components.length);
+
+    for (var i = 0 ; i < components.length ;i++) {
+        log(components[i].name);
+    }
+
+    log("Select components");
+
+    function trim(str) {
+        return str.replace(/^ +/,"").replace(/ *$/,"");
+    }
+
+    var widget = gui.currentPageWidget();
+
+    var packages = trim("$PACKAGES").split(",");
+    if (packages.length > 0 && packages[0] !== "") {
+        widget.deselectAll();
+        for (var i in packages) {
+            var pkg = trim(packages[i]);
+               log("Select " + pkg);
+               widget.selectComponent(pkg);
+        }
+    } else {
+       log("Use default component list");
+    }
+
+    gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.IntroductionPageCallback = function() {
+    log("Introduction Page");
+    log("Retrieving meta information from remote repository");
+    gui.clickButton(buttons.NextButton);
+}
+
+
+Controller.prototype.TargetDirectoryPageCallback = function() {
+    log("Set target installation page: $OUTPUT");
+    var widget = gui.currentPageWidget();
+
+    if (widget != null) {
+        widget.TargetDirectoryLineEdit.setText("$OUTPUT");
+    }
+    
+    gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.LicenseAgreementPageCallback = function() {
+    log("Accept license agreement");
+    var widget = gui.currentPageWidget();
+
+    if (widget != null) {
+        widget.AcceptLicenseRadioButton.setChecked(true);
+    }
+
+    gui.clickButton(buttons.NextButton);
+
+}
+
+Controller.prototype.ReadyForInstallationPageCallback = function() {
+    log("Ready to install");
+    gui.clickButton(buttons.CommitButton);
+}
+
+Controller.prototype.PerformInstallationPageCallback = function() {
+    log("PerformInstallationPageCallback");
+    gui.clickButton(buttons.CommitButton);
+}
+
+Controller.prototype.FinishedPageCallback = function() {
+    var widget = gui.currentPageWidget();
+
+    if (widget.LaunchQtCreatorCheckBoxForm) {
+        // No this form for minimal platform
+        widget.LaunchQtCreatorCheckBoxForm.launchQtCreatorCheckBox.setChecked(false);
+    }
+    gui.clickButton(buttons.FinishButton);
+}
+
+EOF
+
+ARGS="-v"
+
+chmod u+x $1
+
+
+if [ -n "$VERBOSE" ]
+then
+    QT_QPA_PLATFORM=minimal $INSTALLER $ARGS --script $SCRIPT
+else
+    QT_QPA_PLATFORM=minimal $INSTALLER $ARGS --script $SCRIPT | grep "\(QTCI\|operation\)"
+fi
diff --git a/tools/qtci/qt-5.9.5-osx b/tools/qtci/qt-5.9.5-osx
new file mode 100755 (executable)
index 0000000..078ca16
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Reference:
+#   https://github.com/musescore/MuseScore/blob/master/build/travis/job_macos/install.sh
+
+echo Downloading Qt
+set -v
+set -e
+
+DOWNLOAD_URL=https://download.qt.io/archive/qt/5.9/5.9.5/qt-opensource-mac-x64-5.9.5.dmg
+INSTALLER=`basename $DOWNLOAD_URL`
+INSTALLER_NAME=${INSTALLER%.*}
+ENVFILE=qt-5.9.5-osx.env
+APPFILE=/Volumes/${INSTALLER_NAME}/${INSTALLER_NAME}.app/Contents/MacOS/${INSTALLER_NAME}
+echo $INSTALLER_NAME
+echo $APPFILE
+
+wget -nv -c $DOWNLOAD_URL
+hdiutil attach ${INSTALLER}
+ls /Volumes
+echo Installing Qt
+extract-qt-installer $APPFILE $PWD/Qt
+hdiutil detach /Volumes/${INSTALLER_NAME}
+
+echo Create $ENVFILE
+cat << EOF > $ENVFILE
+export PATH=$PWD/Qt/5.9.5/clang_64/bin:$PATH
+EOF
diff --git a/tools/travis_install_osx b/tools/travis_install_osx
new file mode 100755 (executable)
index 0000000..9518a7a
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash -ex
+#
+# This script is run on travis for the install stage of mac builds.
+# Note the script must be sourced if you want the modified PATH to
+# be used outside this script.
+#
+
+# our expectation is that qt-5.9.5-osx creates $QTDIR, $QTDIR/bin.
+QTDIR=${HOME}/Qt/5.9.5/clang_64
+
+if [ -d "${QTDIR}/bin" ]; then
+  echo "Using cached Qt."
+  echo "If you need to clear the cache see"
+  echo "https://docs.travis-ci.com/user/caching/#Fetching-and-storing-caches."
+else
+  pushd ${HOME};
+  rm -fr Qt
+  # qt-5.9.5-osx creates the install at $PWD/Qt.
+  QT_CI_PACKAGES=qt.595.clang_64,qt.595.qtwebengine PATH=${TRAVIS_BUILD_DIR}/tools/qtci:${PATH} qt-5.9.5-osx;
+  popd;
+fi
+# note that qt-5.9.5-osx.env created by qt-5.9.5-osx is not cached!
+export PATH=${QTDIR}/bin:${PATH}
+unset -v QTDIR
diff --git a/tools/travis_script_linux_docker b/tools/travis_script_linux_docker
new file mode 100755 (executable)
index 0000000..22ec02a
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash -ex
+#
+# setup up and run a docker build.
+# this is used by travis.
+#
+# create the container to run the build and regression.
+# pass the compiler from the travis matrix through CC, CXX.
+# we need the default charmap to be UTF-8 for test_encoding_utf8, explicit set it here through LC_ALL.
+cnt=$(docker create  -v `pwd`:/app -e CC=$CC -e CXX=$CXX -e LC_ALL=C.UTF-8 tsteven4/gpsbabel_build_environment bash -c "./build_and_test")
+# copy the pwd to the container.  travis has got the code user test in the pwd.
+docker cp . $cnt:/app
+# run the container to execute the build and the regression.
+docker start -a $cnt
diff --git a/tools/travis_script_osx b/tools/travis_script_osx
new file mode 100755 (executable)
index 0000000..946d0c6
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/bash -ex
+#
+# this script is run on travis for the script stage of mac builds
+#
+
+QMAKE=${QMAKE:-qmake}
+LUPDATE=${LUPDATE:-lupdate}
+LRELEASE=${LRELEASE:-lrelease}
+MACDEPLOYQT=${MACDEPLOYQT:-macdeployqt}
+if [ -z ${VERSIONID+x} ]; then
+  if [ -z "$TRAVIS_BUILD_NUMBER" ]; then
+    VERSIONID=$(git rev-parse --short=7 HEAD)
+  else
+    VERSIONID=${TRAVIS_BUILD_NUMBER}-$(git rev-parse --short=7 HEAD)
+  fi
+fi
+
+# build and test the CLI
+$QMAKE GPSBabel.pro && make && make check
+
+# build the GUI
+pushd gui
+$QMAKE app.pro && make
+$LUPDATE app.pro
+$LRELEASE app.pro
+popd
+
+# package the app
+mkdir -p gui/objects/GPSBabelFE.app/Contents/MacOS/translations
+cp gui/*.qm  gui/objects/gpsbabelFE.app/Contents/MacOS/translations
+cp GPSBabel gui/objects/GPSBabelFE.app/Contents/MacOS/gpsbabel
+cp gui/gmapbase.html gui/objects/GPSBabelFE.app/Contents/MacOS
+cp gui/COPYING.txt gui/objects/GPSBabelFE.app/Contents/MacOS
+tools/mac-localize
+
+rm -f gui/objects/GPSBabelFE.dmg
+pushd gui/objects
+$MACDEPLOYQT GPSBabelFE.app -executable=GPSBabelFE.app/Contents/MacOS/gpsbabel -dmg -verbose=2
+popd
+
+# what is in there?
+hdiutil attach -noverify gui/objects/GPSBabelFE.dmg
+find /Volumes/GPSBabelFE -ls
+hdiutil detach /Volumes/GPSBabelFE
+
+mv gui/objects/GPSBabelFE.dmg gui/objects/GPSBabel-${VERSIONID}.dmg
+
+
diff --git a/tools/uploadtool/LICENSE b/tools/uploadtool/LICENSE
new file mode 100644 (file)
index 0000000..03cdbe7
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Simon Peter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/tools/uploadtool/README.gpsbabel b/tools/uploadtool/README.gpsbabel
new file mode 100644 (file)
index 0000000..55f7014
--- /dev/null
@@ -0,0 +1 @@
+The files README.md, LICENSE, and upload.sh are from https://github.com/probonopd/uploadtool
diff --git a/tools/uploadtool/README.md b/tools/uploadtool/README.md
new file mode 100644 (file)
index 0000000..0a755fc
--- /dev/null
@@ -0,0 +1,41 @@
+# uploadtool [![Build Status](https://travis-ci.org/probonopd/uploadtool.svg?branch=master)](https://travis-ci.org/probonopd/uploadtool)
+
+Super simple uploading of continuous builds (each push) to GitHub Releases. If this is not the easiest way to upload continuous builds to GitHub Releases, then it is a bug.
+
+## Usage
+
+This script is designed to be called from Travis CI after a successful build. By default, this script will _delete_ any pre-existing release tagged with `continuous`, tag the current state with the name `continuous`, create a new release with that name, and upload the specified binaries there. For pull requests, it will upload the binaries to transfer.sh instead and post the resulting download URL to the pull request page on GitHub.
+
+ - On https://github.com/settings/tokens, click on "Generate new token" and generate a token with at least the `public_repo`, `repo:status`, and `repo_deployment` scopes
+ - On Travis CI, go to the settings of your project at `https://travis-ci.org/yourusername/yourrepository/settings`
+ - Under "Environment Variables", add key `GITHUB_TOKEN` and the token you generated above as the value. **Make sure that "Display value in build log" is set to "OFF"!**
+ - In the `.travis.yml` of your GitHub repository, add something like this (assuming the build artifacts to be uploaded are in out/):
+
+```yaml
+after_success:
+  - ls -lh out/* # Assuming you have some files in out/ that you would like to upload
+  - wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
+  - bash upload.sh out/*
+
+branches:
+  except:
+    - # Do not build tags that we create when we upload to GitHub Releases
+    - /^(?i:continuous)$/
+```
+
+## Environment variables
+
+`upload.sh` normally only creates one stream of continuous releases for the latest commits that are pushed into (or merged into) the repository.
+
+It's possible to use `upload.sh` in a more complex manner by setting the environment variable `UPLOADTOOL_SUFFIX`. If this variable is set to the name of the current tag, then `upload.sh` will upload a release to the repository (basically reproducing the `deploy:` feature in `.travis.yml`).
+
+If `UPLOADTOOL_SUFFIX` is set to a different text, then this text is used as suffix for the `continuous` tag that is created for continuous releases. This way, a project can customize what releases are being created.
+One possible use case for this is to set up continuous builds for feature or test branches:
+```
+  if [ ! -z $TRAVIS_BRANCH ] && [ "$TRAVIS_BRANCH" != "master" ] ; then
+    export UPLOADTOOL_SUFFIX=$TRAVIS_BRANCH
+  fi
+```
+This will create builds tagged with `continuous` for pushes / merges to `master` and with `continuous-<branch-name>` for pushes / merges to other branches.
+
+The two environment variables `UPLOADTOOL_PR_BODY` and `UPLOADTOOL_BODY` allow the calling script to customize the messages that are posted either for pull requests or merges / pushes. If these variables aren't set, generic default texts are used.
diff --git a/tools/uploadtool/upload.sh b/tools/uploadtool/upload.sh
new file mode 100755 (executable)
index 0000000..03ee58a
--- /dev/null
@@ -0,0 +1,204 @@
+#!/bin/bash
+
+set +x # Do not leak information
+
+# Exit immediately if one of the files given as arguments is not there
+# because we don't want to delete the existing release if we don't have
+# the new files that should be uploaded 
+for file in "$@"
+do
+    if [ ! -e "$file" ]
+    then echo "$file is missing, giving up." >&2; exit 1
+    fi
+done
+
+if [ $# -eq 0 ]; then
+    echo "No artifacts to use for release, giving up."
+    exit 0
+fi
+
+if command -v sha256sum >/dev/null 2>&1 ; then
+  shatool="sha256sum"
+elif command -v shasum >/dev/null 2>&1 ; then
+  shatool="shasum -a 256" # macOS fallback
+else
+  echo "Neither sha256sum nor shasum is available, cannot check hashes"
+fi
+
+# The calling script (usually .travis.yml) can set a suffix to be used for
+# the tag and release name. This way it is possible to have a release for
+# the output of the CI/CD pipeline (marked as 'continuous') and also test
+# builds for other branches.
+# If this build was triggered by a tag, call the result a Release
+if [ ! -z "$UPLOADTOOL_SUFFIX" ] ; then
+  if [ "$UPLOADTOOL_SUFFIX" = "$TRAVIS_TAG" ] ; then
+    RELEASE_NAME=$TRAVIS_TAG
+    RELEASE_TITLE="Release build ($TRAVIS_TAG)"
+    is_prerelease="false"
+  else
+    RELEASE_NAME="continuous-$UPLOADTOOL_SUFFIX"
+    RELEASE_TITLE="Continuous build ($UPLOADTOOL_SUFFIX)"
+    is_prerelease="true"
+  fi
+else
+  RELEASE_NAME="continuous" # Do not use "latest" as it is reserved by GitHub
+  RELEASE_TITLE="Continuous build"
+  is_prerelease="true"
+fi
+
+if [ "$TRAVIS_EVENT_TYPE" == "pull_request" ] ; then
+  echo "Release uploading disabled for pull requests, uploading to transfer.sh instead"
+  rm -f ./uploaded-to
+  for FILE in "$@" ; do
+    BASENAME="$(basename "${FILE}")"
+    curl --upload-file $FILE "https://transfer.sh/$BASENAME" > ./one-upload
+    echo "$(cat ./one-upload)" # this way we get a newline
+    echo -n "$(cat ./one-upload)\\n" >> ./uploaded-to # this way we get a \n but no newline
+  done
+#  review_url="https://api.github.com/repos/${TRAVIS_REPO_SLUG}/pulls/${TRAVIS_PULL_REQUEST}/reviews"
+#  if [ -z $UPLOADTOOL_PR_BODY ] ; then
+#    body="Travis CI has created build artifacts for this PR here:"
+#  else
+#    body="$UPLOADTOOL_PR_BODY"
+#  fi
+#  body="$body\n$(cat ./uploaded-to)\nThe link(s) will expire 14 days from now."
+#  review_comment=$(curl -X POST \
+#    --header "Authorization: token ${GITHUB_TOKEN}" \
+#    --data '{"commit_id": "'"$TRAVIS_COMMIT"'","body": "'"$body"'","event": "COMMENT"}' \
+#    $review_url)
+#  if echo $review_comment | grep -q "Bad credentials" 2>/dev/null ; then
+#    echo '"Bad credentials" response for --data {"commit_id": "'"$TRAVIS_COMMIT"'","body": "'"$body"'","event": "COMMENT"}'
+#  fi
+  $shatool "$@"
+  exit 0
+fi
+
+if [ ! -z "$TRAVIS_REPO_SLUG" ] ; then
+  # We are running on Travis CI
+  echo "Running on Travis CI"
+  echo "TRAVIS_COMMIT: $TRAVIS_COMMIT"
+  REPO_SLUG="$TRAVIS_REPO_SLUG"
+  if [ -z "$GITHUB_TOKEN" ] ; then
+    echo "\$GITHUB_TOKEN missing, please set it in the Travis CI settings of this project"
+    echo "You can get one from https://github.com/settings/tokens"
+    exit 1
+  fi
+else
+  # We are not running on Travis CI
+  echo "Not running on Travis CI"
+  if [ -z "$REPO_SLUG" ] ; then
+    read -r -s -p "Repo Slug (GitHub and Travis CI username/reponame): " REPO_SLUG
+  fi
+  if [ -z "$GITHUB_TOKEN" ] ; then
+    read -r -s -p "Token (https://github.com/settings/tokens): " GITHUB_TOKEN
+  fi
+fi
+
+tag_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
+tag_infos=$(curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${tag_url}")
+echo "tag_infos: $tag_infos"
+tag_sha=$(echo "$tag_infos" | grep '"sha":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "tag_sha: $tag_sha"
+
+release_url="https://api.github.com/repos/$REPO_SLUG/releases/tags/$RELEASE_NAME"
+echo "Getting the release ID..."
+echo "release_url: $release_url"
+release_infos=$(curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${release_url}")
+echo "release_infos: $release_infos"
+release_id=$(echo "$release_infos" | grep "\"id\":" | head -n 1 | tr -s " " | cut -f 3 -d" " | cut -f 1 -d ",")
+echo "release ID: $release_id"
+upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "upload_url: $upload_url"
+release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "release_url: $release_url"
+target_commit_sha=$(echo "$release_infos" | grep '"target_commitish":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "target_commit_sha: $target_commit_sha"
+
+if [ "$TRAVIS_COMMIT" != "$target_commit_sha" ] ; then
+
+  echo "TRAVIS_COMMIT != target_commit_sha, hence deleting $RELEASE_NAME..."
+  
+  if [ ! -z "$release_id" ]; then
+    delete_url="https://api.github.com/repos/$REPO_SLUG/releases/$release_id"
+    echo "Delete the release..."
+    echo "delete_url: $delete_url"
+    curl -XDELETE \
+        --header "Authorization: token ${GITHUB_TOKEN}" \
+        "${delete_url}"
+  fi
+
+  # echo "Checking if release with the same name is still there..."
+  # echo "release_url: $release_url"
+  # curl -XGET --header "Authorization: token ${GITHUB_TOKEN}" \
+  #     "$release_url"
+
+  if [ "$is_prerelease" = "true" ] ; then
+    # if this is a continuous build tag, then delete the old tag
+    # in preparation for the new release
+    echo "Delete the tag..."
+    delete_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
+    echo "delete_url: $delete_url"
+    curl -XDELETE \
+        --header "Authorization: token ${GITHUB_TOKEN}" \
+        "${delete_url}"
+  fi
+
+  echo "Create release..."
+
+  if [ -z "$TRAVIS_BRANCH" ] ; then
+    TRAVIS_BRANCH="master"
+  fi
+
+  if [ ! -z "$TRAVIS_JOB_ID" ] ; then
+    if [ ! -z "$UPLOADTOOL_BODY" ] ; then
+      BODY="Travis CI build log: https://travis-ci.org/$REPO_SLUG/builds/$TRAVIS_BUILD_ID/"
+    else
+      BODY="$UPLOADTOOL_BODY"
+    fi
+  else
+    BODY=""
+  fi
+
+  release_infos=$(curl -H "Authorization: token ${GITHUB_TOKEN}" \
+       --data '{"tag_name": "'"$RELEASE_NAME"'","target_commitish": "'"$TRAVIS_COMMIT"'","name": "'"$RELEASE_TITLE"'","body": "'"$BODY"'","draft": false,"prerelease": '$is_prerelease'}' "https://api.github.com/repos/$REPO_SLUG/releases")
+
+  echo "$release_infos"
+
+  unset upload_url
+  upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+  echo "upload_url: $upload_url"
+
+  unset release_url
+  release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+  echo "release_url: $release_url"
+
+fi # if [ "$TRAVIS_COMMIT" != "$tag_sha" ]
+
+if [ -z "$release_url" ] ; then
+       echo "Cannot figure out the release URL for $RELEASE_NAME"
+       exit 1
+fi
+
+echo "Upload binaries to the release..."
+
+for FILE in "$@" ; do
+  FULLNAME="${FILE}"
+  BASENAME="$(basename "${FILE}")"
+  curl -H "Authorization: token ${GITHUB_TOKEN}" \
+       -H "Accept: application/vnd.github.manifold-preview" \
+       -H "Content-Type: application/octet-stream" \
+       --data-binary @$FULLNAME \
+       "$upload_url?name=$BASENAME"
+  echo ""
+done
+
+$shatool "$@"
+
+if [ "$TRAVIS_COMMIT" != "$tag_sha" ] ; then
+  echo "Publish the release..."
+
+  release_infos=$(curl -H "Authorization: token ${GITHUB_TOKEN}" \
+       --data '{"draft": false}' "$release_url")
+
+  echo "$release_infos"
+fi # if [ "$TRAVIS_COMMIT" != "$tag_sha" ]
diff --git a/tools/uploadtool/upload_appveyor.sh b/tools/uploadtool/upload_appveyor.sh
new file mode 100755 (executable)
index 0000000..4ca2227
--- /dev/null
@@ -0,0 +1,205 @@
+#!/bin/bash
+
+set +x # Do not leak information
+
+# Exit immediately if one of the files given as arguments is not there
+# because we don't want to delete the existing release if we don't have
+# the new files that should be uploaded 
+for file in "$@"
+do
+    if [ ! -e "$file" ]
+    then echo "$file is missing, giving up." >&2; exit 1
+    fi
+done
+
+if [ $# -eq 0 ]; then
+    echo "No artifacts to use for release, giving up."
+    exit 0
+fi
+
+if command -v sha256sum >/dev/null 2>&1 ; then
+  shatool="sha256sum"
+elif command -v shasum >/dev/null 2>&1 ; then
+  shatool="shasum -a 256" # macOS fallback
+else
+  echo "Neither sha256sum nor shasum is available, cannot check hashes"
+fi
+
+# The calling script (usually appveyor.yml) can set a suffix to be used for
+# the tag and release name. This way it is possible to have a release for
+# the output of the CI/CD pipeline (marked as 'continuous') and also test
+# builds for other branches.
+# If this build was triggered by a tag, call the result a Release
+if [ ! -z "$UPLOADTOOL_SUFFIX" ] ; then
+  if [ "$UPLOADTOOL_SUFFIX" = "$APPVEYOR_REPO_TAG_NAME" ] ; then
+    RELEASE_NAME=$APPVEYOR_REPO_TAG_NAME
+    RELEASE_TITLE="Release build ($APPVEYOR_REPO_TAG_NAME)"
+    is_prerelease="false"
+  else
+    RELEASE_NAME="continuous-$UPLOADTOOL_SUFFIX"
+    RELEASE_TITLE="Continuous build ($UPLOADTOOL_SUFFIX)"
+    is_prerelease="true"
+  fi
+else
+  RELEASE_NAME="continuous-windows" # Do not use "latest" as it is reserved by GitHub
+  RELEASE_TITLE="Continuous build"
+  is_prerelease="true"
+fi
+
+#if [ "$TRAVIS_EVENT_TYPE" == "pull_request" ] ; then
+if [ -v APPVEYOR_PULL_REQUEST_NUMBER ]; then
+  echo "Release uploading disabled for pull requests, uploading to transfer.sh instead"
+  rm -f ./uploaded-to
+  for FILE in "$@" ; do
+    BASENAME="$(basename "${FILE}")"
+    curl -s -S --upload-file $FILE "https://transfer.sh/$BASENAME" > ./one-upload
+    echo "$(cat ./one-upload)" # this way we get a newline
+    echo -n "$(cat ./one-upload)\\n" >> ./uploaded-to # this way we get a \n but no newline
+  done
+#  review_url="https://api.github.com/repos/${APPVEYOR_REPO_NAME}/pulls/${APPVEYOR_PULL_REQUEST_NUMBER}/reviews"
+#  if [ -z $UPLOADTOOL_PR_BODY ] ; then
+#    body="Appveyor CI has created build artifacts for this PR here:"
+#  else
+#    body="$UPLOADTOOL_PR_BODY"
+#  fi
+#  body="$body\n$(cat ./uploaded-to)\nThe link(s) will expire 14 days from now."
+#  review_comment=$(curl -s -S -X POST \
+#    --header "Authorization: token ${GITHUB_TOKEN}" \
+#    --data '{"commit_id": "'"$APPVEYOR_REPO_COMMIT"'","body": "'"$body"'","event": "COMMENT"}' \
+#    $review_url)
+#  if echo $review_comment | grep -q "Bad credentials" 2>/dev/null ; then
+#    echo '"Bad credentials" response for --data {"commit_id": "'"$APPVEYOR_REPO_COMMIT"'","body": "'"$body"'","event": "COMMENT"}'
+#  fi
+  $shatool "$@"
+  exit 0
+fi
+
+if [ ! -z "$APPVEYOR_REPO_NAME" ] ; then
+  # We are running on Appveyor CI
+  echo "Running on Appveyor CI"
+  echo "APPVEYOR_REPO_COMMIT: $APPVEYOR_REPO_COMMIT"
+  REPO_SLUG="$APPVEYOR_REPO_NAME"
+  if [ -z "$GITHUB_TOKEN" ] ; then
+    echo "\$GITHUB_TOKEN missing, please set it in the Appveyor CI settings of this project"
+    echo "You can get one from https://github.com/settings/tokens"
+    exit 1
+  fi
+else
+  # We are not running on Appveyor CI
+  echo "Not running on Appveyor CI"
+  if [ -z "$REPO_SLUG" ] ; then
+    read -r -s -p "Repo Slug (GitHub and Appveyor CI username/reponame): " REPO_SLUG
+  fi
+  if [ -z "$GITHUB_TOKEN" ] ; then
+    read -r -s -p "Token (https://github.com/settings/tokens): " GITHUB_TOKEN
+  fi
+fi
+
+tag_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
+tag_infos=$(curl -s -S -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${tag_url}")
+echo "tag_infos: $tag_infos"
+tag_sha=$(echo "$tag_infos" | grep '"sha":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "tag_sha: $tag_sha"
+
+release_url="https://api.github.com/repos/$REPO_SLUG/releases/tags/$RELEASE_NAME"
+echo "Getting the release ID..."
+echo "release_url: $release_url"
+release_infos=$(curl -s -S -XGET --header "Authorization: token ${GITHUB_TOKEN}" "${release_url}")
+echo "release_infos: $release_infos"
+release_id=$(echo "$release_infos" | grep "\"id\":" | head -n 1 | tr -s " " | cut -f 3 -d" " | cut -f 1 -d ",")
+echo "release ID: $release_id"
+upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "upload_url: $upload_url"
+release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "release_url: $release_url"
+target_commit_sha=$(echo "$release_infos" | grep '"target_commitish":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+echo "target_commit_sha: $target_commit_sha"
+
+if [ "$APPVEYOR_REPO_COMMIT" != "$target_commit_sha" ] ; then
+
+  echo "APPVEYOR_REPO_COMMIT != target_commit_sha, hence deleting $RELEASE_NAME..."
+  
+  if [ ! -z "$release_id" ]; then
+    delete_url="https://api.github.com/repos/$REPO_SLUG/releases/$release_id"
+    echo "Delete the release..."
+    echo "delete_url: $delete_url"
+    curl -s -S -XDELETE \
+        --header "Authorization: token ${GITHUB_TOKEN}" \
+        "${delete_url}"
+  fi
+
+  # echo "Checking if release with the same name is still there..."
+  # echo "release_url: $release_url"
+  # curl -s -S -XGET --header "Authorization: token ${GITHUB_TOKEN}" \
+  #     "$release_url"
+
+  if [ "$is_prerelease" = "true" ] ; then
+    # if this is a continuous build tag, then delete the old tag
+    # in preparation for the new release
+    echo "Delete the tag..."
+    delete_url="https://api.github.com/repos/$REPO_SLUG/git/refs/tags/$RELEASE_NAME"
+    echo "delete_url: $delete_url"
+    curl -s -S -XDELETE \
+        --header "Authorization: token ${GITHUB_TOKEN}" \
+        "${delete_url}"
+  fi
+
+  echo "Create release..."
+
+  if [ -z "$APPVEYOR_REPO_BRANCH" ] ; then
+    APPVEYOR_REPO_BRANCH="master"
+  fi
+
+  if [ ! -z "$APPVEYOR_JOB_ID" ] ; then
+    if [ ! -z "$UPLOADTOOL_BODY" ] ; then
+      BODY="Appveyor CI build log: https://ci.appveyor.com/project/$REPO_SLUG/build/$APPVEYOR_BUILD_VERSION/"
+    else
+      BODY="$UPLOADTOOL_BODY"
+    fi
+  else
+    BODY=""
+  fi
+
+  release_infos=$(curl -s -S -H "Authorization: token ${GITHUB_TOKEN}" \
+       --data '{"tag_name": "'"$RELEASE_NAME"'","target_commitish": "'"$APPVEYOR_REPO_COMMIT"'","name": "'"$RELEASE_TITLE"'","body": "'"$BODY"'","draft": false,"prerelease": '$is_prerelease'}' "https://api.github.com/repos/$REPO_SLUG/releases")
+
+  echo "$release_infos"
+
+  unset upload_url
+  upload_url=$(echo "$release_infos" | grep '"upload_url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+  echo "upload_url: $upload_url"
+
+  unset release_url
+  release_url=$(echo "$release_infos" | grep '"url":' | head -n 1 | cut -d '"' -f 4 | cut -d '{' -f 1)
+  echo "release_url: $release_url"
+
+fi # if [ "$APPVEYOR_REPO_COMMIT" != "$tag_sha" ]
+
+if [ -z "$release_url" ] ; then
+       echo "Cannot figure out the release URL for $RELEASE_NAME"
+       exit 1
+fi
+
+echo "Upload binaries to the release..."
+
+for FILE in "$@" ; do
+  FULLNAME="${FILE}"
+  BASENAME="$(basename "${FILE}")"
+  curl -s -S -H "Authorization: token ${GITHUB_TOKEN}" \
+       -H "Accept: application/vnd.github.manifold-preview" \
+       -H "Content-Type: application/octet-stream" \
+       --data-binary @$FULLNAME \
+       "$upload_url?name=$BASENAME"
+  echo ""
+done
+
+$shatool "$@"
+
+if [ "$APPVEYOR_REPO_COMMIT" != "$tag_sha" ] ; then
+  echo "Publish the release..."
+
+  release_infos=$(curl -s -S -H "Authorization: token ${GITHUB_TOKEN}" \
+       --data '{"draft": false}' "$release_url")
+
+  echo "$release_infos"
+fi # if [ "$APPVEYOR_REPO_COMMIT" != "$tag_sha" ]